package hn.cch.apache.commons.math3;

import org.apache.commons.math3.linear.Array2DRowRealMatrix;
import org.apache.commons.math3.linear.ArrayRealVector;
import org.apache.commons.math3.linear.CholeskyDecomposition;
import org.apache.commons.math3.linear.DecompositionSolver;
import org.apache.commons.math3.linear.EigenDecomposition;
import org.apache.commons.math3.linear.LUDecomposition;
import org.apache.commons.math3.linear.MatrixUtils;
import org.apache.commons.math3.linear.QRDecomposition;
import org.apache.commons.math3.linear.RealMatrix;
import org.apache.commons.math3.linear.RealVector;
import org.apache.commons.math3.linear.SingularValueDecomposition;
import org.junit.Test;

public class TestMatrix {

    @Test
    public void test() {
        double[][] a1 = {{4, 1, 2}, {1, 4, 2}, {1, 2, 4}};
        double[][] a2 = {{0, 0, -1}, {0, -2, 0}, {-3, 0, 0}};
        RealMatrix m1 = new Array2DRowRealMatrix(a1);
        RealMatrix m2 = new Array2DRowRealMatrix(a2);

        RealMatrix m3 = m1.add(m2);
        System.out.println(m1.scalarAdd(10));         // Array2DRowRealMatrix{{14.0,11.0,12.0},{11.0,14.0,12.0},{11.0,12.0,14.0}}
        // 减法
        System.out.println(m1.subtract(m2));         // Array2DRowRealMatrix{{4.0,1.0,3.0},{1.0,6.0,2.0},{4.0,2.0,4.0}}
        // 乘法
        // 后乘
        System.out.println(m1.multiply(m2));         // Array2DRowRealMatrix{{-6.0,-2.0,-4.0},{-6.0,-8.0,-1.0},{-12.0,-4.0,-1.0}}
        // 矩阵乘以一个常数
        System.out.println(m1.scalarMultiply(10));         // Array2DRowRealMatrix{{40.0,10.0,20.0},{10.0,40.0,20.0},{10.0,20.0,40.0}}
        // 前乘
        System.out.println(m1.preMultiply(m2));         // Array2DRowRealMatrix{{-1.0,-2.0,-4.0},{-2.0,-8.0,-4.0},{-12.0,-3.0,-6.0}}

        // 转置
        System.out.println(m1.transpose());         // Array2DRowRealMatrix{{4.0,1.0,1.0},{1.0,4.0,2.0},{2.0,2.0,4.0}}

        // 计算矩阵迹
        System.out.println(m1.getTrace());         // 12.0

        // 获取矩阵二范数
        System.out.println(m1.getNorm());         // 8

        // 获取矩阵Frobenius范数
        System.out.println(m1.getFrobeniusNorm());        // 7.937253933193772

        // 获取矩阵指定索引处元素
        System.out.println(m1.getEntry(1, 2));         // 2.0

        // 获取子矩阵
        System.out.println(m1.getSubMatrix(new int[]{0, 2}, new int[]{0, 2}));         // Array2DRowRealMatrix{{4.0,2.0},{1.0,4.0}}


        System.out.println(MatrixUtils.inverse(m1));
        //BlockRealMatrix{{0.2857142857,0.0,-0.1428571429},{-0.0476190476,0.3333333333,-0.1428571429},{-0.0476190476,-0.1666666667,0.3571428571}}

        LUDecomposition luDecomposition = new LUDecomposition(m1);
        System.out.println(luDecomposition.getL()); // Array2DRowRealMatrix{{1.0,0.0,0.0},{0.25,1.0,0.0},{0.25,0.4666666667,1.0}}
        System.out.println(luDecomposition.getU()); // Array2DRowRealMatrix{{4.0,1.0,2.0},{0.0,3.75,1.5},{0.0,0.0,2.8}}

        // 基于LU分解求解方阵行列式值
        System.out.println(luDecomposition.getDeterminant()); // 42.0

        // 基于LU分解求解线性方程组 Ax = b
        RealVector v1 = new ArrayRealVector(new double[]{1, 2, 3}); // 常数项
        DecompositionSolver solver1 = luDecomposition.getSolver();
        System.out.println(solver1.solve(v1)); //{-0.1428571429; 0.1904761905; 0.6904761905}

        QRDecomposition qrDecomposition = new QRDecomposition(m1);
        System.out.println(qrDecomposition.getQ());//Array2DRowRealMatrix{{-0.9428090416,0.3110026075,0.1199520288},{-0.2357022604,-0.876461894,0.4198321007},{-0.2357022604,-0.3675485362,-0.8996402159}}
        System.out.println(qrDecomposition.getR());//Array2DRowRealMatrix{{-4.2426406871,-2.357022604,-3.2998316455},{0.0,-3.9299420409,-2.6011127177},{0.0,0.0,-2.5189926044}}
        System.out.println(qrDecomposition.getQ().multiply(qrDecomposition.getR()));//Array2DRowRealMatrix{{4.0,1.0,2.0},{1.0,4.0,2.0},{1.0,2.0,4.0}}

        //基于QR分解求解线性方程
        DecompositionSolver solver = qrDecomposition.getSolver();
        System.out.println(solver.solve(v1)); //{-0.1428571429; 0.1904761905; 0.6904761905}


        SingularValueDecomposition singularValueDecomposition = new SingularValueDecomposition(m1);
        System.out.println(singularValueDecomposition.getS()); //Array2DRowRealMatrix{{7.0545956017,0.0,0.0},{0.0,3.0826433447,0.0},{0.0,0.0,1.9313184371}}
        System.out.println(singularValueDecomposition.getVT()); //Array2DRowRealMatrix{{0.4744437695,0.5795264045,0.6626101841},{-0.8226982328,0.5596928501,0.0995566733},{-0.3131624615,-0.5923622709,0.7423181345}}
        System.out.println(singularValueDecomposition.getU()); //Array2DRowRealMatrix{{0.5390134411,-0.8213686928,-0.1865957685},{0.5837003265,0.5239615271,-0.6202888416},{0.6072548388,0.225428012,0.7618554799}}
        System.out.println(singularValueDecomposition.getU().multiply(singularValueDecomposition.getS()).
                multiply(singularValueDecomposition.getVT()));//Array2DRowRealMatrix{{4.0,1.0,2.0},{1.0,4.0,2.0},{1.0,2.0,4.0}}
        //基于奇异值分解求解线性方程组
        DecompositionSolver solver2 = singularValueDecomposition.getSolver();
        System.out.println(solver2.solve(v1));//{-0.1428571429; 0.1904761905; 0.6904761905}


        EigenDecomposition eigenDecomposition = new EigenDecomposition(m1);
        System.out.println(eigenDecomposition.getD()); //Array2DRowRealMatrix{{3.0,0.0,0.0},{0.0,7.0,0.0},{0.0,0.0,2.0}}
        System.out.println(eigenDecomposition.getV()); //Array2DRowRealMatrix{{-0.9045340337,0.58630197,-0.5656854249},{0.3015113446,0.58630197,-0.5656854249},{0.3015113446,0.58630197,0.8485281374}}

        //创造对称矩阵
        RealMatrix m6 = new Array2DRowRealMatrix(new double[][]{{4, 1, 1}, {1, 4, 1}, {1, 1, 4}});
        CholeskyDecomposition choleskyDecomposition = new CholeskyDecomposition(m6);
        System.out.println(choleskyDecomposition.getL()); //Array2DRowRealMatrix{{2.0,0.0,0.0},{0.5,1.9364916731,0.0},{0.5,0.3872983346,1.8973665961}}
        DecompositionSolver solver3 = choleskyDecomposition.getSolver();
        System.out.println(solver3.solve(v1)); //{0; 0.3333333333; 0.6666666667}

    }


}
